package com.ruoyi.web.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.enums.ReportSummeryType;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.math.MathUtils;
import com.ruoyi.system.service.ISysDictTypeService;
import com.ruoyi.web.dao.ReportSummeryDao;
import com.ruoyi.web.entity.CaseInfoEntity;
import com.ruoyi.web.entity.ExcelMode;
import com.ruoyi.web.entity.ReportSummeryEntity;
import com.ruoyi.web.entity.SmallClassMode;
import com.ruoyi.web.listener.CaseInfoExcelListener;
import com.ruoyi.web.mapper.CaseInfoMapper;
import com.ruoyi.web.service.CaseInfoService;
import com.ruoyi.web.service.ReportSummerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ：wang.j.f
 * @description：TODO
 * @date ：Created in 2021/6/20 11:18
 * @modified By：
 * @version: 1.0.$
 */
@Service
@Slf4j
public class CaseInfoServiceImpl implements CaseInfoService {

    @Resource
    private CaseInfoMapper caseInfoMapper;
    @Autowired
    private ISysDictTypeService sysDictTypeService;
    @Autowired
    private ReportSummerService reportSummerService;
    @Resource
    private ReportSummeryDao reportSummeryDao;
    @Value("${common.http-prefix}")
    private String HttpPrefix;



    @Override
    public void insertBatch(List<CaseInfoEntity> caseInfoEntities) {
        caseInfoMapper.insertBatch(caseInfoEntities);
    }

    @Override
    @Transactional
    public String importExcelToDb(MultipartFile file,
                                  @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate today,
                                  Integer workDays,
                                  Integer statType,
                                  HttpServletResponse response) {
        ExcelReader reader = null;
        try {
            CaseInfoExcelListener caseInfoExcelListener = new CaseInfoExcelListener();
            reader = EasyExcel.read(file.getInputStream(), CaseInfoEntity.class, caseInfoExcelListener).build();
            ReadSheet readSheet = EasyExcel
                    .readSheet(0)
                    // 第二行为表头
                    .headRowNumber(2)
                    .build();

            reader = reader.read(readSheet);
            List<CaseInfoEntity> caseInfoEntities = caseInfoExcelListener.getLocalCaseInfos().get();
            LinkedHashMap<String, Long> collect = caseInfoEntities.stream().collect(Collectors.groupingBy(CaseInfoEntity::getSmallClass, LinkedHashMap::new, Collectors.counting()));
            collect = collect.entrySet().stream().sorted(new Comparator<Map.Entry<String, Long>>() {
                @Override
                public int compare(Map.Entry<String, Long> o1, Map.Entry<String, Long> o2) {
                    return - o1.getValue().compareTo(o2.getValue());
                }
            }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue)-> oldValue, LinkedHashMap::new));
            List<SmallClassMode> smallClassModes = new ArrayList<>();

            for (Map.Entry<String, Long> stringLongEntry : collect.entrySet()) {
                if (smallClassModes.size() == 6) break;
                SmallClassMode smallClassMode = new SmallClassMode();
                smallClassMode.setClassName(stringLongEntry.getKey());
                smallClassMode.setNum(stringLongEntry.getValue());
                smallClassModes.add(smallClassMode);
            }

            // 上报汇总
            List<ReportSummeryEntity> reportSummeryEntities = summeryReport(caseInfoEntities, today, workDays, statType);
            Long sum = reportSummeryEntities.stream().mapToInt(ReportSummeryEntity::getWgzNum).summaryStatistics().getSum();
            // 入库本周总上报统计
            ReportSummeryEntity reportSummeryEntity = new ReportSummeryEntity();
            reportSummeryEntity.setUnitName("合计");
            reportSummeryEntity.setWgzNum(sum.intValue());
            reportSummeryEntity.setShouldDoneNumWeekly(reportSummeryEntity.getWgzNum() * workDays);
            reportSummeryEntity.setTotalReportNum(caseInfoExcelListener.getActualReportNum());
            reportSummeryEntity.setEffectiveReportNum(caseInfoExcelListener.getEffectiveReportNum());

            reportSummeryEntity.setEffectiveReportRate(MathUtils.divide(reportSummeryEntity.getEffectiveReportNum().longValue(), reportSummeryEntity.getTotalReportNum().longValue(), 4).movePointRight(2));
            reportSummeryEntity.setEffectiveCompleteRate(MathUtils.divide(reportSummeryEntity.getEffectiveReportNum().longValue(), reportSummeryEntity.getShouldDoneNumWeekly().longValue(), 4).movePointRight(2));
            LocalDate firstDay = null;
            LocalDate lastDay = null;
            if (statType == 1) {
                firstDay = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                lastDay = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
            } else if (statType == 2) {
                firstDay = today.with(TemporalAdjusters.firstDayOfMonth());
                lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
            }
            reportSummeryEntity.setReportTime(firstDay + "," + lastDay);
            reportSummeryEntity.setType(ReportSummeryType.TOTAL_WEEK.getCode());
            insertBatch(caseInfoExcelListener.getLocalCaseInfos().get());
            List<ReportSummeryEntity> list = new ArrayList<>();
            list.add(reportSummeryEntity);
            reportSummeryDao.batchAdd(list);
//            reportSummerService.insert(reportSummeryEntity);
            LocalDate first = null;
            LocalDate last = null;
            List<ReportSummeryEntity> totalSummeryByTime = null;
            if (statType == 1){
                LocalDate todayOfLastWeek = today.minusDays(7);
                // 按周
                first = todayOfLastWeek.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                last = todayOfLastWeek.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
                totalSummeryByTime = reportSummerService.getTotalSummeryByTime(first + "," + last, ReportSummeryType.TOTAL_WEEK.getCode());
            } else if (statType == 2) {
                // 按月
                // 先获取本月第一天
                LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
                last = firstDayOfMonth.minusDays(1);
                first = last.with(TemporalAdjusters.firstDayOfMonth());
                totalSummeryByTime = reportSummerService.getTotalSummeryByTime(first + "," + last, ReportSummeryType.TOTAL_MONTH.getCode());
            }
            BigDecimal increaseReportRate = new BigDecimal(0);
            BigDecimal increaseCompleteRate = new BigDecimal(0);
            // 有效上报率环比和有效完成率环比
            if (!CollectionUtils.isEmpty(totalSummeryByTime)) {
                BigDecimal effectiveReportRate = totalSummeryByTime.get(0).getEffectiveReportRate();
                BigDecimal effectiveCompleteRate = totalSummeryByTime.get(0).getEffectiveCompleteRate();
                increaseReportRate =  reportSummeryEntity.getEffectiveReportRate().subtract(effectiveReportRate);
                increaseCompleteRate = reportSummeryEntity.getEffectiveCompleteRate().subtract(effectiveCompleteRate);
            }
            // 正在处置
            Integer processingReportNum = reportSummeryEntity.getTotalReportNum() - caseInfoExcelListener.getClosedReportNum() - caseInfoExcelListener.getInvalidReportNum();
            caseInfoExcelListener.setProcessingReportNum(processingReportNum);
            StringBuffer sb = new StringBuffer();
            sb.append("全区网格通应上报数:").append(reportSummeryEntity.getShouldDoneNumWeekly()).append("件\n")
                    .append("实际上报数:").append(reportSummeryEntity.getTotalReportNum()).append("件\n")
                    .append("有效上报数:").append(reportSummeryEntity.getEffectiveReportNum()).append("件\n")
                    .append("有效上报率:").append(reportSummeryEntity.getEffectiveReportRate()).append("%\n");
            if (increaseReportRate.compareTo(new BigDecimal(0)) >= 0) {
                sb.append("环比增加了:").append(increaseReportRate).append("个百分点\n");
            }
            if (increaseReportRate.compareTo(new BigDecimal(0)) < 0) {
                sb.append("环比减少了:").append(increaseReportRate.abs()).append("个百分点\n");
            }
            sb.append("有效完成率:").append(reportSummeryEntity.getEffectiveCompleteRate()).append("%\n");
            if (increaseCompleteRate.compareTo(new BigDecimal(0)) >= 0) {
                sb.append("环比增加了:").append(increaseCompleteRate).append("个百分点\n");
            }
            if (increaseCompleteRate.compareTo(new BigDecimal(0)) < 0) {
                sb.append("环比减少了:").append(increaseCompleteRate.abs()).append("个百分点\n");
            }
            sb.append("已结案:").append(caseInfoExcelListener.getClosedReportNum()).append("件\n")
                .append("正在处置:").append(caseInfoExcelListener.getProcessingReportNum()).append("件\n")
                .append("作废:").append(caseInfoExcelListener.getInvalidReportNum()).append("件\n");
//            for (int i = 0; i < 15; i++) {
//                ReportSummeryEntity reportSummeryEntity1 = reportSummeryEntities.get(i);
//                sb.append("单位名称:").append(reportSummeryEntity1.getUnitName()).append(" ")
//                        .append("网格长数量:").append(reportSummeryEntity1.getWgzNum()).append(" ")
//                        .append("周应完成数:").append(reportSummeryEntity1.getShouldDoneNumWeekly()).append(" ")
//                        .append("总上报数:").append(reportSummeryEntity1.getTotalReportNum()).append(" ")
//                        .append("有效上报数:").append(reportSummeryEntity1.getEffectiveReportNum()).append(" ")
//                        .append("有效上报率:").append(reportSummeryEntity1.getEffectiveReportRate()).append(" ")
//                        .append("有效完成率:").append(reportSummeryEntity1.getEffectiveCompleteRate()).append(" \n");
//            }
//            log.info(sb.toString());
//            response.setHeader("Content-Disposition", "attachment;fileName=" + UUID.randomUUID().toString() + ".xlsx");
//            response.setHeader("content-type", "application/vnd.ms-excel;charset=UTF-8");
//            response.setContentType("application/force-download");
//            OutputStream outputStream = response.getOutputStream();
            // 文件路径
            String filePath = RuoYiConfig.getProfile() + File.separator + UUID.randomUUID() + ".xlsx";
            File file1 = new File(filePath);
            FileUtils.touch(file1);
            ExcelWriter excelWriter = null;
            try {
                excelWriter = EasyExcel.write(file1).build();
                WriteSheet writeSheet = EasyExcel.writerSheet(0, "汇总数据").head(ReportSummeryEntity.class).build();
                reportSummeryEntities.add(reportSummeryEntity);
                excelWriter.write(reportSummeryEntities, writeSheet);

                WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "总结").head(ExcelMode.class).build();
                List<ExcelMode> list1 = new ArrayList<>();
                ExcelMode excelMode = new ExcelMode();
                excelMode.setZj(sb.toString());
                list1.add(excelMode);
                excelWriter.write(list1, writeSheet1);

                WriteSheet writeSheet2 = EasyExcel.writerSheet(2, "小类").head(SmallClassMode.class).build();
                excelWriter.write(smallClassModes, writeSheet2);
            } finally {
                if (excelWriter != null) {
                    excelWriter.finish();
                }
            }
//            EasyExcel.write(file1, ReportSummeryEntity.class).sheet(0).sheetName("汇总数据").doWrite(reportSummeryEntities);
//            List<String> list1 = new ArrayList<>();
//            list1.add(sb.toString());
//            EasyExcel.write(file1).sheet(1).needHead(false).sheetName("总结").doWrite(list1);
            return filePath.replace(RuoYiConfig.getProfile() + File.separator, HttpPrefix + Constants.RESOURCE_PREFIX + File.separator);
//            response.flushBuffer();
        } catch (IOException e) {
            log.info("导入失败，请联系管理员");
            return null;
        } finally {
            reader.finish();
        }
    }

    public void exportExcel (HttpServletResponse response) {
        try {
            OutputStream outputStream = response.getOutputStream();
            EasyExcel.write(outputStream, ReportSummeryEntity.class);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public List<ReportSummeryEntity> summeryReport(List<CaseInfoEntity> list, LocalDate today, Integer workDays, Integer statType) {
        // 根据街道分组得到每个街道的总上报数
        Map<String, Long> totalReportMap = list.stream().collect(Collectors.groupingBy(CaseInfoEntity::getStreet, Collectors.counting()));

        // 每个街道有效上报数
        Map<String, Long> effectiveReportMap = list.stream().filter(caseInfoEntity -> !"作废".equals(caseInfoEntity.getStatus()))
                .collect(Collectors.groupingBy(CaseInfoEntity::getStreet, Collectors.counting()));

        // 网格长数量
        List<SysDictData> wgzNum = sysDictTypeService.selectDictDataByType("wgz_num");

        List<ReportSummeryEntity> summerList = new ArrayList<>();
        wgzNum.forEach(sysDictData -> {
            ReportSummeryEntity reportSummeryEntity = new ReportSummeryEntity();
            String street = sysDictData.getDictLabel();
            reportSummeryEntity.setUnitName(street);
            reportSummeryEntity.setWgzNum(Integer.valueOf(sysDictData.getDictValue()));
            reportSummeryEntity.setShouldDoneNumWeekly(reportSummeryEntity.getWgzNum() * workDays);
            reportSummeryEntity.setTotalReportNum(Math.toIntExact(totalReportMap.get(street)));
            reportSummeryEntity.setEffectiveReportNum(Math.toIntExact(effectiveReportMap.get(street)));
            reportSummeryEntity.setEffectiveReportRate(MathUtils.divide(reportSummeryEntity.getEffectiveReportNum().longValue(), reportSummeryEntity.getTotalReportNum().longValue(), 4).movePointRight(2));
            reportSummeryEntity.setEffectiveCompleteRate(MathUtils.divide(reportSummeryEntity.getEffectiveReportNum().longValue(), reportSummeryEntity.getShouldDoneNumWeekly().longValue(), 4).movePointRight(2));
            LocalDate firstDay = null;
            LocalDate lastDay = null;
            if (statType == 1) {
                firstDay = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
                lastDay = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
            } else if (statType == 2) {
                firstDay = today.with(TemporalAdjusters.firstDayOfMonth());
                lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
            }
            reportSummeryEntity.setReportTime(firstDay + "," + lastDay);
            reportSummeryEntity.setType(ReportSummeryType.BY_STREET_WEEK.getCode());
            summerList.add(reportSummeryEntity);
        });
        summerList.sort(new Comparator<ReportSummeryEntity>() {
            @Override
            public int compare(ReportSummeryEntity o1, ReportSummeryEntity o2) {
                return - o1.getEffectiveCompleteRate().compareTo(o2.getEffectiveCompleteRate());
            }
        });
        reportSummerService.batchInsert(summerList);
        return summerList;
    }

    public static void main(String[] args) throws IOException {

    }

}
